﻿using Microsoft.EntityFrameworkCore;
using Microsoft.VisualBasic;
using Polaris.Common;
using Polaris.Domain.Interfaces.Admin;
using Polaris.Domain.Interfaces.WebSite;
using Polaris.Domain.Model.DbEntity;
using Polaris.Domain.Model.Dto.Notes.Response;
using Polaris.Domain.Model.DtoWebSite.Comments.Request;
using Polaris.Domain.Model.DtoWebSite.Comments.Response;
using Polaris.Domain.Model.Entity.Base;
using Polaris.Domain.Model.Entity.Exception;
using Polaris.Domain.Repository.Interfaces;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;

namespace Polaris.Infrastructure.DomainService.WebSite
{
    public class WebCommentsService : IWebComments
    {
        private static readonly CultureInfo zhCulture = CultureInfo.GetCultureInfo("zh-CN");
        private const string DateFormat = "yyyy年MM月dd日 dddd";
        private readonly IBaseRepository<UnifyMessage> _unifyMessage;

        public WebCommentsService(IBaseRepository<UnifyMessage> unifyMessage)
        {
            _unifyMessage = unifyMessage;
        }

        /// <summary>
        /// 文章评论
        /// </summary>
        /// <param name="create"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<CommentsInfoResponse> AuditComments(CreateCommentsRequest create)
        {
            try
            {
                string externalIp = await IpHandler.GetExternalIPAddressAsync();
                var ipInfo = IpHandler.IpGetCity(externalIp).Split("|", StringSplitOptions.None);
                var position = $"{(ipInfo.Length > 0 ? ipInfo[0] : "")} {(ipInfo.Length > 2 ? ipInfo[2] : "")} {(ipInfo.Length > 3 ? ipInfo[3] : "")}";

                var comm = new UnifyMessage()
                {
                    Anonymous = create.Anonymous,
                    Content = create.Content,
                    CreateTime = DateTime.Now,
                    Examine = true,
                    MessageType = create.MessageType,
                    ParentId = string.IsNullOrEmpty(create.ParentId) ? null : Guid.Parse(create.ParentId),
                    TypeId = string.IsNullOrEmpty(create.TypeId) ? null : Guid.Parse(create.TypeId),
                    UserEmail = create.UserEmail,
                    UserName = create.UserName,
                    WebSite = create.WebSite,
                    ReplyId = string.IsNullOrEmpty(create.ReplyId) ? null : Guid.Parse(create.ReplyId),
                    IPAddress = externalIp,
                    Position = position
                };
                await _unifyMessage.AddEntityAsync(comm);
                await _unifyMessage.CommitAsync();

                var result = new CommentsInfoResponse()
                {
                    TypeId = comm.TypeId.HasValue ? comm.TypeId.ToString() : null,
                    Anonymous = comm.Anonymous,
                    Browser = comm.Browser,
                    Content = comm.Content,
                    CreateTime = FormatTime(comm.CreateTime),
                    DeviceInfo = comm.DeviceInfo,
                    Examine = comm.Examine,
                    IPAddress = comm.IPAddress,
                    ParentId = comm.ParentId.HasValue ? comm.ParentId.ToString() : null,
                    Position = comm.Position,
                    UserEmail = comm.UserEmail,
                    UserName = comm.UserName,
                    WebSite = comm.WebSite,
                    ReplyId = comm.ReplyId,
                    Id = comm.Id.ToString()
                };
                if (comm.ReplyId.HasValue)
                {
                    result.ReplyName = _unifyMessage.QueryAll(d => d.Id == comm.ReplyId.Value).FirstOrDefault()?.UserName;
                }
                return result;
            }
            catch (Exception ex)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.FAIL, ex.Message);
            }
        }

        /// <summary>
        /// 获取文章下的评论
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<PaginationInfo<CommentsInfoResponse>> GetCommentsByArticle(CommentsPagedRequest pageInfo)
        {
            try
            {
                int total = 0;
                var data = await _unifyMessage.QueryAll(out total, pageInfo.PageIndex, pageInfo.PageSize, d => d.CreateTime, false, d => d.TypeId == Guid.Parse(pageInfo.Id) && d.ParentId == null)
                    .OrderByDescending(d => d.CreateTime)
                    .Select(d => new CommentsInfoResponse()
                    {
                        TypeId = d.TypeId.HasValue ? d.TypeId.ToString() : null,
                        Anonymous = d.Anonymous,
                        Browser = d.Browser,
                        Content = d.Content,
                        CreateTime = FormatTime(d.CreateTime),
                        DeviceInfo = d.DeviceInfo,
                        Examine = d.Examine,
                        IPAddress = d.IPAddress,
                        ParentId = d.ParentId.HasValue ? d.ParentId.ToString() : null,
                        Position = d.Position,
                        UserEmail = d.UserEmail,
                        UserName = d.UserName,
                        WebSite = d.WebSite,
                        ReplyId = d.ReplyId,
                        Id = d.Id.ToString()
                    })
                    .ToListAsync();

                var pIds = data.Select(d => Guid.Parse(d.Id)).ToList();
                var childrenList = await _unifyMessage.QueryAll(d => d.ParentId != null && pIds.Contains(d.ParentId.Value)).ToListAsync();
                var replyIds = new List<Guid?>();
                var comments = new List<CommentsInfoResponse>();
                foreach (var item in data)
                {
                    var children = childrenList.Where(d => d.ParentId.Value == Guid.Parse(item.Id))
                         .Select(d => new CommentsInfoResponse()
                         {
                             TypeId = d.TypeId.HasValue ? d.TypeId.ToString() : null,
                             Anonymous = d.Anonymous,
                             Browser = d.Browser,
                             Content = d.Content,
                             CreateTime = FormatTime(d.CreateTime),
                             DeviceInfo = d.DeviceInfo,
                             Examine = d.Examine,
                             IPAddress = d.IPAddress,
                             ParentId = d.ParentId.HasValue ? d.ParentId.ToString() : null,
                             Position = d.Position,
                             UserEmail = d.UserEmail,
                             UserName = d.Anonymous == true ? "消失的名字" : d.UserName,
                             WebSite = d.WebSite,
                             ReplyId = d.ReplyId,
                             Id = d.Id.ToString()
                         })
                         .ToList();
                    replyIds.AddRange(children.Select(d => d.ReplyId));
                    item.Children = children;
                    comments.Add(item);

                }
                var dict1 = childrenList.Where(d => replyIds.Contains(d.Id))
                    .ToDictionary(d => d.Id, d => d.Anonymous == true ? "消失的名字" : d.UserName);
                var dict2 = data.Where(d => replyIds.Contains(Guid.Parse(d.Id)))
                    .ToDictionary(d => Guid.Parse(d.Id), d => d.Anonymous == true ? "消失的名字" : d.UserName);
                var replyIdNames = dict2
                    .Concat(dict1)
                    .GroupBy(pair => pair.Key)
                    .ToDictionary(g => g.Key, g => g.First().Value);

                foreach (var item in comments)
                {
                    foreach (var e in item.Children)
                    {
                        if (replyIdNames.TryGetValue(e.ReplyId.Value, out var userName))
                        {
                            e.ReplyName = userName;
                        }
                    }
                }
                return ApiResult
                    .CreatePaginationInfo<CommentsInfoResponse>(
                                                                PageIndex: pageInfo.PageIndex,
                                                                PageSize: pageInfo.PageSize,
                                                                Total: total,
                                                                Result: comments
                                                             );
            }
            catch (Exception ex)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.FAIL, ex.Message);
            }
        }

        /// <summary>
        /// 格式时间
        /// </summary>
        /// <param name="createTime"></param>
        /// <returns></returns>
        private static string FormatTime(DateTime createTime)
        {
            DateTime now = DateTime.Now;
            TimeSpan difference = now - createTime;

            // 处理未来时间
            if (difference.TotalSeconds < 0)
                return createTime.ToString(DateFormat, zhCulture);

            // 层级判断
            if (difference.TotalSeconds < 60)          // 1分钟内
                return "刚刚";
            else if (difference.TotalMinutes < 30)     // 30分钟内
                return $"{(int)difference.TotalMinutes}分钟前";
            else if (difference.TotalMinutes > 30 && difference.TotalMinutes < 60) // 半小时
                return $"半小时前";
            else if (difference.TotalHours < 24)       // 24小时内
                return $"{(int)difference.TotalHours}小时前";
            else if (difference.TotalDays < 10)        // 10天内
                return $"{(int)difference.TotalDays}天前";
            else                                       // 超过10天
                return createTime.ToString(DateFormat, zhCulture);

        }
    }
}
